home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 41 / Amiga Format CD41 (1999-06)(Future Publishing)(GB)[!][issue 1999-07].iso / -seriously_amiga- / programming / other / gtlayout / source / ltp_popupclass.c < prev    next >
C/C++ Source or Header  |  1999-04-19  |  26KB  |  1,285 lines

  1. /*
  2. **    GadTools layout toolkit
  3. **
  4. **    Copyright © 1993-1998 by Olaf `Olsen' Barthel
  5. **        Freely distributable.
  6. **
  7. **    :ts=4
  8. */
  9.  
  10. #ifndef _GTLAYOUT_GLOBAL_H
  11. #include "gtlayout_global.h"
  12. #endif
  13.  
  14. /*****************************************************************************/
  15.  
  16. #include <intuition/classes.h>
  17.  
  18. #include <clib/alib_protos.h>    /* For Coerce/Do/DoSuperMethod */
  19.  
  20. /*****************************************************************************/
  21.  
  22. #include "Assert.h"
  23.  
  24. /*****************************************************************************/
  25.  
  26. #ifdef DO_POPUP_KIND    /* Support code */
  27.  
  28. #define PIF_SingleActive    (1 << 0)
  29. #define PIF_ArrowUp            (1 << 1)
  30. #define PIF_ArrowDown        (1 << 2)
  31.  
  32. STATIC VOID
  33. DrawArrow(
  34.     struct RastPort *    RPort,
  35.     LONG                Left,
  36.     LONG                Top,
  37.     LONG                ArrowWidth,
  38.     LONG                ArrowHeight,
  39.     LONG                Dir)
  40. {
  41.     LONG i,Width,Start,Pos;
  42.  
  43.     for(i = 0 ; i < ArrowHeight ; i++)
  44.     {
  45.         Width = ((ArrowWidth * (i + 1)) / ArrowHeight) & ~1;
  46.  
  47.         if(Width < ArrowWidth)
  48.             Width++;
  49.  
  50.         Start = Left + (ArrowWidth - Width) / 2;
  51.  
  52.         if(Dir < 0)
  53.             Pos = Top + i;
  54.         else
  55.             Pos = Top + ArrowHeight - 1 - i;
  56.  
  57.         LTP_DrawLine(RPort,Start,Pos,Start + Width - 1,Pos);
  58.     }
  59. }
  60.  
  61. STATIC VOID
  62. DrawContainer(
  63.     struct RastPort *    RPort,
  64.     LONG                Left,
  65.     LONG                Top,
  66.     LONG                Width,
  67.     LONG                Height,
  68.     struct GadgetInfo *    GadgetInfo,
  69.     PopInfo *            Info,
  70.     UWORD                Highlight,
  71.     UWORD                Disabled)
  72. {
  73.     LONG Shine,Shadow,Txt,Fill;
  74.     LONG Right;
  75.     UWORD * Pens;
  76.  
  77.     Pens = GadgetInfo->gi_DrInfo->dri_Pens;
  78.  
  79.     if(Highlight)
  80.     {
  81.         Shine    = Pens[SHADOWPEN];
  82.         Shadow    = Pens[SHINEPEN];
  83.         Txt        = Pens[FILLTEXTPEN];
  84.         Fill    = Pens[FILLPEN];
  85.     }
  86.     else
  87.     {
  88.         Shine    = Pens[SHINEPEN];
  89.         Shadow    = Pens[SHADOWPEN];
  90.         Txt        = Pens[TEXTPEN];
  91.         Fill    = Pens[BACKGROUNDPEN];
  92.     }
  93.  
  94.     LTP_SetPens(RPort,Fill,0,JAM1);
  95.  
  96.     if(Info->FrameImage != NULL)
  97.     {
  98.         DrawImageState(RPort,Info->FrameImage,Left,Top,Highlight ? IDS_SELECTED : IDS_NORMAL,GadgetInfo->gi_DrInfo);
  99.     }
  100.     else
  101.     {
  102.         LTP_FillBox(RPort,Left + 2,Top + 1,Width - 4,Height - 2);
  103.         LTP_RenderBevel(RPort,Pens,Left,Top,Width,Height,Highlight,2);
  104.     }
  105.  
  106.     Right = Left + Width - Info->MarkLeft;
  107.  
  108.     LTP_SetAPen(RPort,Shadow);
  109.     LTP_DrawLine(RPort,Right,Top + 2,Right,Top + Height - 3);
  110.  
  111.     LTP_SetAPen(RPort,Shine);
  112.     LTP_DrawLine(RPort,Right + 1,Top + 2,Right + 1,Top + Height - 3);
  113.  
  114.     SetFont(RPort,Info->Font);
  115.     LTP_SetAPen(RPort,Txt);
  116.  
  117.     LTP_DrawAdjustedPicker(RPort,FALSE,Right + 2,Top,Info->PickerWidth,Height,Info->AspectX,Info->AspectY);
  118.  
  119.     LTP_PrintText(RPort,Info->Labels[Info->Active],Info->ActiveLen,Left + 6,Top + Info->LabelTop);
  120.  
  121.     if(Disabled)
  122.         LTP_GhostBox(RPort,Left,Top,Width,Height,Pens[SHADOWPEN]);
  123. }
  124.  
  125. STATIC VOID
  126. DrawOneBox(
  127.     PopInfo *    Info,
  128.     LONG        Top,
  129.     LONG        Index)
  130. {
  131.     struct RastPort    *    RPort;
  132.     LONG                Len;
  133.     LONG                Extra;
  134.     STRPTR                Label;
  135.  
  136.     Label = Info->Labels[Index];
  137.  
  138.     RPort = Info->Window->RPort;
  139.  
  140.     if((Len = strlen(Label)) > Info->MaxLen)
  141.         Len = Info->MaxLen;
  142.  
  143.     if(Info->CheckGlyph)
  144.         Extra = Info->CheckGlyph->Width + 2;
  145.     else
  146.         Extra = 0;
  147.  
  148.     LTP_PrintText(RPort,Label,Len,6 + Extra,Top + Info->LineTop);
  149.  
  150.     if(Extra && Index == Info->InitialActive)
  151.         LTP_DrawCheckGlyph(RPort,6,Top + Info->LineTop,Info->CheckGlyph,Index == Info->LastLabelDrawn);
  152. }
  153.  
  154. STATIC VOID
  155. DrawOneGlyph(
  156.     PopInfo *    Info,
  157.     LONG        Top,
  158.     LONG        Dir,
  159.     UWORD *        Pens)
  160. {
  161.     struct RastPort *RPort;
  162.  
  163.     RPort = Info->Window->RPort;
  164.  
  165.     if(Pens != NULL)
  166.     {
  167.         LTP_SetAPen(RPort,Info->MenuBack);
  168.         LTP_FillBox(RPort,4,Top,Info->SingleWidth,Info->SingleHeight);
  169.         LTP_SetAPen(RPort,Info->MenuText);
  170.     }
  171.  
  172.     DrawArrow(RPort,6,Top + Info->ArrowTop,Info->ArrowWidth,Info->ArrowHeight,Dir);
  173. }
  174.  
  175. STATIC VOID
  176. BoxRender(
  177.     PopInfo *    Info,
  178.     UWORD *        Pens,
  179.     LONG        Active,
  180.     BOOL        FullRefresh,
  181.     BOOL        Highlight,
  182.     LONG        Dir)
  183. {
  184.     struct RastPort *RPort = Info->Window->RPort;
  185.  
  186.     if(FullRefresh)
  187.     {
  188.         LONG Index,Top;
  189.         LONG Width,Height;
  190.  
  191.         LTP_SetPens(RPort,Info->MenuBack,0,JAM1);
  192.  
  193.         Width    = Info->Window->Width;
  194.         Height    = Info->Window->Height;
  195.  
  196.         LTP_FillBox(RPort,2,1,Width - 4,Height - 2);
  197.  
  198.         LTP_SetAPen(RPort,Info->MenuText);
  199.  
  200.         LTP_PolyDraw(RPort,5,
  201.             1,1,
  202.             1,Height - 2,
  203.             0,Height - 2,
  204.             0,0,
  205.             Width - 1,0);
  206.  
  207.         LTP_PolyDraw(RPort,5,
  208.             0,Height - 1,
  209.             Width - 1,Height - 1,
  210.             Width - 1,1,
  211.             Width - 2,1,
  212.             Width - 2,Height - 2);
  213.  
  214.         Index    = Info->TopMost;
  215.         Top        = 2;
  216.         Height    = Info->BoxHeight;
  217.  
  218.         Info->Flags &= ~(PIF_ArrowUp | PIF_ArrowDown);
  219.  
  220.         if(Info->TopMost > 0 && Active != Info->TopMost && Info->BoxLines > 2)
  221.         {
  222.             Info->Flags |= PIF_ArrowUp;
  223.  
  224.             Index    += 1;
  225.             Top        += Info->SingleHeight;
  226.             Height    -= Info->SingleHeight;
  227.         }
  228.  
  229.         if(Info->TopMost + Info->BoxLines < Info->NumLabels && Active != Info->TopMost + Info->BoxLines - 1 && Info->BoxLines > 2)
  230.         {
  231.             Info->Flags |= PIF_ArrowDown;
  232.  
  233.             Height -= Info->SingleHeight;
  234.         }
  235.  
  236.         Info->LastLabelDrawn = Active;    // IMPORTANT: must be set up here to DrawOneBox can find it
  237.  
  238.         for(NULL ; Index < Info->NumLabels && Height > 0 ; Index++, Top += Info->SingleHeight, Height -= Info->SingleHeight)
  239.         {
  240.             if(Index == Active)
  241.             {
  242.                 LTP_SetAPen(RPort,Info->MenuBackSelect);
  243.                 LTP_FillBox(RPort,4,Top,Info->SingleWidth,Info->SingleHeight);
  244.  
  245.                 LTP_SetAPen(RPort,Info->MenuTextSelect);
  246.                 DrawOneBox(Info,Top,Index);
  247.  
  248.                 LTP_SetAPen(RPort,Info->MenuText);
  249.             }
  250.             else
  251.             {
  252.                 DrawOneBox(Info,Top,Index);
  253.             }
  254.         }
  255.  
  256.         if(Info->Flags & PIF_ArrowUp)
  257.             DrawOneGlyph(Info,2,-1,NULL);
  258.  
  259.         if(Info->Flags & PIF_ArrowDown)
  260.             DrawOneGlyph(Info,2 + (Info->BoxLines - 1) * Info->SingleHeight,1,NULL);
  261.  
  262.         Info->LastDrawn = 2 + (Active - Info->TopMost) * Info->SingleHeight;
  263.     }
  264.     else
  265.     {
  266.         if(Info->LastLabelDrawn != -1)
  267.         {
  268.             LONG Top = Info->LastDrawn,Last = Info->LastLabelDrawn;
  269.  
  270.             Info->LastLabelDrawn = -1;
  271.  
  272.             LTP_SetPens(RPort,Info->MenuBack,0,JAM1);
  273.             LTP_FillBox(RPort,4,Top,Info->SingleWidth,Info->SingleHeight);
  274.             LTP_SetAPen(RPort,Info->MenuText);
  275.  
  276.             DrawOneBox(Info,Top,Last);
  277.         }
  278.  
  279.         Info->LastDrawn = -1;
  280.  
  281.         if(Active >= 0)
  282.         {
  283.             LONG Top,NewActive;
  284.  
  285.             NewActive    = Active - Info->TopMost;
  286.             Top            = 2 + NewActive * Info->SingleHeight;
  287.  
  288.             if(Top >= 2 && Top < Info->BoxHeight + 2)
  289.             {
  290.                 LONG Pen;
  291.  
  292.                 if(Dir != 0)
  293.                     Highlight = FALSE;
  294.  
  295.                 if(Highlight)
  296.                 {
  297.                     Pen = Info->MenuBackSelect;
  298.  
  299.                     Info->LastDrawn            = Top;
  300.                     Info->LastLabelDrawn    = Active;
  301.                 }
  302.                 else
  303.                 {
  304.                     Pen = Info->MenuBack;
  305.                 }
  306.  
  307.                 LTP_SetPens(RPort,Pen,0,JAM1);
  308.                 LTP_FillBox(RPort,4,Top,Info->SingleWidth,Info->SingleHeight);
  309.  
  310.                 if(Highlight)
  311.                     Pen = Info->MenuTextSelect;
  312.                 else
  313.                     Pen = Info->MenuText;
  314.  
  315.                 LTP_SetAPen(RPort,Pen);
  316.  
  317.                 if(Dir == 0)
  318.                     DrawOneBox(Info,Top,Active);
  319.                 else
  320.                     DrawOneGlyph(Info,Top,Dir,NULL);
  321.             }
  322.         }
  323.     }
  324. }
  325.  
  326. STATIC ULONG
  327. InputMethod(
  328.     struct IClass *        class,
  329.     struct Gadget *        gadget,
  330.     struct gpInput *    InputInfo)
  331. {
  332.     PopInfo    *Info    = INST_DATA(class,gadget);
  333.     ULONG     Result    = GMR_MEACTIVE;
  334.     BOOL     Done    = FALSE;
  335.     BOOL     Redraw    = FALSE;
  336.  
  337.     if(InputInfo->gpi_IEvent->ie_Class == IECLASS_RAWMOUSE)
  338.     {
  339.         UWORD Code = InputInfo->gpi_IEvent->ie_Code;
  340.  
  341.         if(Code == MENUDOWN)
  342.         {
  343.             Result    = GMR_NOREUSE;
  344.             Done    = TRUE;
  345.  
  346.             Info->Active = Info->InitialActive;
  347.         }
  348.         else
  349.         {
  350.             if(Code == SELECTUP)
  351.             {
  352.                 Done = TRUE;
  353.  
  354.                 if(Info->Active < 0)
  355.                 {
  356.                     Result = GMR_NOREUSE;
  357.  
  358.                     Info->Active = Info->InitialActive;
  359.                 }
  360.                 else
  361.                 {
  362.                     LONG Len;
  363.  
  364.                     Result = GMR_NOREUSE | GMR_VERIFY;
  365.  
  366.                     if(Info->Flags & PIF_SingleActive)
  367.                     {
  368.                         LONG Width,Height;
  369.                         LONG x,y;
  370.  
  371.                         x = InputInfo->gpi_Mouse.X;
  372.                         y = InputInfo->gpi_Mouse.Y;
  373.  
  374.                         Width    = gadget->Width;
  375.                         Height    = gadget->Height;
  376.  
  377.                         if(x >= 0 && y >= 0 && x < Width && y < Height)
  378.                         {
  379.                             if(InputInfo->gpi_IEvent->ie_Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT))
  380.                                 Info->Active--;
  381.                             else
  382.                                 Info->Active++;
  383.  
  384.                             if(Info->Active >= Info->NumLabels)
  385.                             {
  386.                                 Info->Active = 0;
  387.                             }
  388.                             else
  389.                             {
  390.                                 if(Info->Active < 0)
  391.                                     Info->Active = Info->NumLabels - 1;
  392.                             }
  393.                         }
  394.                         else
  395.                         {
  396.                             Result = GMR_NOREUSE;
  397.  
  398.                             Info->Active = Info->InitialActive;
  399.                         }
  400.                     }
  401.  
  402.                     Len = strlen(Info->Labels[Info->Active]);
  403.  
  404.                     if(Len > Info->MaxLen)
  405.                         Len = Info->MaxLen;
  406.  
  407.                     Info->ActiveLen = Len;
  408.  
  409.                     (*InputInfo->gpi_Termination) = Info->Active;
  410.                 }
  411.             }
  412.             else
  413.             {
  414.                 if(Info->Flags & PIF_SingleActive)
  415.                 {
  416.                     LONG Width,Height;
  417.                     LONG x,y;
  418.                     BOOL RefreshIt = FALSE;
  419.  
  420.                     x = InputInfo->gpi_Mouse.X;
  421.                     y = InputInfo->gpi_Mouse.Y;
  422.  
  423.                     Width    = gadget->Width;
  424.                     Height    = gadget->Height;
  425.  
  426.                     if(x < 0 || y < 0 || x >= Width || y >= Height)
  427.                     {
  428.                         if(gadget->Flags & GFLG_SELECTED)
  429.                             RefreshIt = TRUE;
  430.                     }
  431.                     else
  432.                     {
  433.                         if(!(gadget->Flags & GFLG_SELECTED))
  434.                             RefreshIt = TRUE;
  435.                     }
  436.  
  437.                     if(RefreshIt)
  438.                     {
  439.                         gadget->Flags ^= GFLG_SELECTED;
  440.  
  441.                         Redraw = TRUE;
  442.                     }
  443.                 }
  444.             }
  445.         }
  446.  
  447.         if(Done)
  448.         {
  449.             if(gadget->Flags & GFLG_SELECTED)
  450.             {
  451.                 gadget->Flags &= ~GFLG_SELECTED;
  452.                 Redraw = TRUE;
  453.             }
  454.  
  455.             if(Info->Window != NULL)
  456.             {
  457.                 CloseWindow(Info->Window);
  458.                 Info->Window = NULL;
  459.             }
  460.  
  461.             LTP_DeleteCheckGlyph(Info->CheckGlyph);
  462.             Info->CheckGlyph = NULL;
  463.  
  464.             Info->Flags &= ~PIF_SingleActive;
  465.         }
  466.     }
  467.  
  468.     if(!Done && Info->Window)
  469.     {
  470.         LONG NewActive = 0;
  471.         LONG x,y;
  472.         LONG Dir = 0;
  473.         LONG From = 0,To = 0;    /* Initialize these for the sake of the compiler. */
  474.  
  475.         x = InputInfo->gpi_GInfo->gi_Screen->MouseX - Info->BoxLeft;
  476.         y = InputInfo->gpi_GInfo->gi_Screen->MouseY - Info->BoxTop;
  477.  
  478.         if(x < 0 || x >= Info->BoxWidth)
  479.         {
  480.             NewActive = -1;
  481.         }
  482.         else
  483.         {
  484.             LONG Margin;
  485.  
  486.             if(Info->Flags & (PIF_ArrowUp | PIF_ArrowDown))
  487.                 Margin = Info->SingleHeight;
  488.             else
  489.                 Margin = (Info->SingleHeight + 3) / 4;
  490.  
  491.                 // Scroll up?
  492.  
  493.             if(y < Margin)
  494.             {
  495.                 if(y < 0)
  496.                 {
  497.                     NewActive = -1;
  498.                 }
  499.                 else
  500.                 {
  501.                         // Topmost line concealed?
  502.  
  503.                     if(Info->TopMost > 0)
  504.                     {
  505.                         Info->TopMost--;
  506.  
  507.                         From    = 2;
  508.                         To        = 2 + Info->BoxHeight - 1;
  509.  
  510.                         Dir = -Info->SingleHeight;
  511.                     }
  512.                 }
  513.             }
  514.             else
  515.             {
  516.                 LONG Last;
  517.  
  518.                 Last = Info->NumLabels - Info->TopMost;
  519.  
  520.                 if(Last < Info->BoxLines)
  521.                     Last = Last * Info->SingleHeight;
  522.                 else
  523.                     Last = Info->BoxHeight;
  524.  
  525.                     // Scroll up?
  526.  
  527.                 if(y >= Last - Margin)
  528.                 {
  529.                     if(y >= Last)
  530.                     {
  531.                         NewActive = -1;
  532.                     }
  533.                     else
  534.                     {
  535.                             // Last line concealed?
  536.  
  537.                         if(Info->TopMost + Info->BoxLines < Info->NumLabels)
  538.                         {
  539.                             Info->TopMost++;
  540.  
  541.                             From    = 2;
  542.                             To        = 2 + Info->BoxHeight - 1;
  543.  
  544.                             Dir = Info->SingleHeight;
  545.                         }
  546.                     }
  547.                 }
  548.             }
  549.  
  550.             if(NewActive != -1)
  551.             {
  552.                 NewActive = Info->TopMost + y / Info->SingleHeight;
  553.  
  554.                 if(NewActive < 0)
  555.                 {
  556.                     NewActive = 0;
  557.                 }
  558.                 else
  559.                 {
  560.                     if(NewActive >= Info->NumLabels)
  561.                         NewActive = Info->NumLabels - 1;
  562.                 }
  563.             }
  564.         }
  565.  
  566.         if(NewActive != Info->Active || Dir != 0)
  567.         {
  568.             LONG    Arrow;
  569.             UWORD *    Pens = InputInfo->gpi_GInfo->gi_DrInfo->dri_Pens;
  570.  
  571.             if(Dir != 0)
  572.             {
  573.                 struct RastPort *RPort = Info->Window->RPort;
  574.  
  575.                 Arrow = (NewActive == Info->TopMost) ? -1 : 1;
  576.  
  577.                 BoxRender(Info,Pens,-1,FALSE,FALSE,0);
  578.  
  579.                 if(Info->Flags & PIF_ArrowUp)
  580.                     From += Info->SingleHeight;
  581.  
  582.                 if(Info->Flags & PIF_ArrowDown)
  583.                     To -= Info->SingleHeight;
  584.  
  585.                 SetBPen(RPort,Pens[BACKGROUNDPEN]);
  586.                 ScrollRaster(RPort,0,Dir,4,From,4 + Info->BoxWidth - 1,To);
  587.  
  588.                 if(Dir < 0)
  589.                     BoxRender(Info,Pens,Info->TopMost + 1,FALSE,FALSE,0);
  590.                 else
  591.                     BoxRender(Info,Pens,Info->TopMost + Info->BoxLines - 2,FALSE,FALSE,0);
  592.  
  593.                 if(!Info->TopMost || Info->BoxLines < 3)
  594.                 {
  595.                     Info->Flags &= ~PIF_ArrowUp;
  596.  
  597.                     Arrow = 0;
  598.                 }
  599.                 else
  600.                 {
  601.                     if(!(Info->Flags & PIF_ArrowUp))
  602.                     {
  603.                         Info->Flags |= PIF_ArrowUp;
  604.  
  605.                         DrawOneGlyph(Info,2,-1,Pens);
  606.                     }
  607.                 }
  608.  
  609.                 if(Info->TopMost + Info->BoxLines >= Info->NumLabels || Info->BoxLines < 3)
  610.                 {
  611.                     Info->Flags &= ~PIF_ArrowDown;
  612.  
  613.                     Arrow = 0;
  614.                 }
  615.                 else
  616.                 {
  617.                     if(!(Info->Flags & PIF_ArrowDown))
  618.                     {
  619.                         Info->Flags |= PIF_ArrowDown;
  620.  
  621.                         DrawOneGlyph(Info,2 + (Info->BoxLines - 1) * Info->SingleHeight,1,Pens);
  622.                     }
  623.                 }
  624.             }
  625.             else
  626.             {
  627.                 Arrow = 0;
  628.             }
  629.  
  630.             Info->Active = NewActive;
  631.  
  632.             BoxRender(Info,Pens,NewActive,FALSE,TRUE,Arrow);
  633.         }
  634.     }
  635.  
  636.     if(Redraw)
  637.     {
  638.         struct RastPort    * RPort;
  639.  
  640.         RPort = ObtainGIRPort(InputInfo->gpi_GInfo);
  641.         if(RPort != NULL)
  642.         {
  643.             DoMethod((Object *)gadget,GM_RENDER,InputInfo->gpi_GInfo,RPort,GREDRAW_UPDATE);
  644.             ReleaseGIRPort(RPort);
  645.         }
  646.     }
  647.  
  648.     return(Result);
  649. }
  650.  
  651. STATIC VOID
  652. SetMethod(
  653.     struct IClass *    class,
  654.     struct Gadget *    gadget,
  655.     struct opSet *    SetInfo)
  656. {
  657.     PopInfo *            Info = INST_DATA(class,gadget);
  658.     struct TagItem *    This;
  659.     LONG                NewActive;
  660.     STRPTR *            NewLabels;
  661.     UWORD                Flags = gadget -> Flags;
  662.     BOOL                NeedRefresh = FALSE;
  663.     LONG                LabelCount;
  664.  
  665.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  666.  
  667.     DoSuperMethodA(class,(Object *)gadget,(Msg)SetInfo);
  668.  
  669.     if((This = FindTagItem(GA_Disabled,SetInfo->ops_AttrList)) != NULL)
  670.     {
  671.         if(This -> ti_Data && !(Flags & GFLG_DISABLED) || !This -> ti_Data && (Flags & GFLG_DISABLED))
  672.             NeedRefresh = TRUE;
  673.     }
  674.  
  675.     NewLabels = (STRPTR *)GetTagData(PIA_Labels,NULL,SetInfo->ops_AttrList);
  676.     if(NewLabels != NULL)
  677.     {
  678.         for(LabelCount = 0 ; NewLabels[LabelCount] != NULL ; LabelCount++)
  679.             NULL;
  680.     }
  681.     else
  682.     {
  683.         LabelCount = Info->NumLabels;
  684.     }
  685.  
  686.     if((This = FindTagItem(PIA_Active,SetInfo->ops_AttrList)) != NULL)
  687.     {
  688.         NewActive = (LONG)This->ti_Data;
  689.  
  690.         if(NewActive < 0)
  691.         {
  692.             NewActive = 0;
  693.         }
  694.         else
  695.         {
  696.             if(NewActive >= LabelCount)
  697.                 NewActive = LabelCount - 1;
  698.         }
  699.     }
  700.     else
  701.     {
  702.         NewActive = -1;
  703.     }
  704.  
  705.     if((NewActive != Info->Active && NewActive != -1) || (NewLabels != NULL))
  706.     {
  707.         if(NewLabels == (STRPTR *)~0)
  708.         {
  709.             Info->Blocked = TRUE;
  710.         }
  711.         else
  712.         {
  713.             struct RastPort *RPort;
  714.  
  715.             Info->Blocked = FALSE;
  716.  
  717.             RPort = ObtainGIRPort(SetInfo->ops_GInfo);
  718.             if(RPort != NULL)
  719.             {
  720.                 LONG        Len;
  721.                 STRPTR *    Labels;
  722.                 LONG        MaxLen,ActiveLen;
  723.  
  724.                 if(NewLabels != NULL)
  725.                 {
  726.                     struct TextExtent Extent;
  727.                     LONG i;
  728.  
  729.                     for(i = 0, MaxLen = 0 ; i < LabelCount ; i++)
  730.                     {
  731.                         Len = TextFit(RPort,NewLabels[i],strlen(NewLabels[i]),&Extent,NULL,1,Info->MaxWidth,32767);
  732.  
  733.                         if(Len > MaxLen)
  734.                             MaxLen = Len;
  735.                     }
  736.  
  737.                     Labels = NewLabels;
  738.                 }
  739.                 else
  740.                 {
  741.                     Labels = Info->Labels;
  742.                     MaxLen = Info->MaxLen;
  743.                 }
  744.  
  745.                 if(NewActive == -1)
  746.                     NewActive = Info->Active;
  747.  
  748.                 if(NewActive >= LabelCount)
  749.                     NewActive = LabelCount - 1;
  750.  
  751.                 Len = strlen(Labels[NewActive]);
  752.  
  753.                 if(Len > MaxLen)
  754.                     Len = MaxLen;
  755.  
  756.                 ActiveLen = Len;
  757.  
  758.                 Info->Active    = NewActive;
  759.                 Info->ActiveLen    = ActiveLen;
  760.  
  761.                 if(NewLabels != NULL)
  762.                 {
  763.                     Info->Labels    = NewLabels;
  764.                     Info->NumLabels    = LabelCount;
  765.                     Info->MaxLen    = MaxLen;
  766.                 }
  767.  
  768.                 NeedRefresh = TRUE;
  769.  
  770.                 ReleaseGIRPort(RPort);
  771.             }
  772.         }
  773.     }
  774.  
  775.     if(!(gadget -> Flags & GFLG_DISABLED) && (This = FindTagItem(PIA_Highlight,SetInfo->ops_AttrList)))
  776.     {
  777.         if(This->ti_Data)
  778.             gadget->Flags |= GFLG_SELECTED;
  779.         else
  780.             gadget->Flags &= ~GFLG_SELECTED;
  781.  
  782.         NeedRefresh = TRUE;
  783.     }
  784.  
  785.     if(NeedRefresh)
  786.     {
  787.         struct RastPort *RPort;
  788.  
  789.         if(RPort = ObtainGIRPort(SetInfo->ops_GInfo))
  790.         {
  791.             DoMethod((Object *)gadget,GM_RENDER,SetInfo->ops_GInfo,RPort,GREDRAW_UPDATE);
  792.             ReleaseGIRPort(RPort);
  793.         }
  794.     }
  795. }
  796.  
  797. STATIC ULONG
  798. RenderMethod(
  799.     struct IClass *        class,
  800.     struct Gadget *        gadget,
  801.     struct gpRender *    RenderInfo)
  802. {
  803.     PopInfo    *Info = INST_DATA(class,gadget);
  804.  
  805.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  806.  
  807.     DrawContainer(RenderInfo->gpr_RPort,gadget->LeftEdge,gadget->TopEdge,gadget->Width,gadget->Height,RenderInfo->gpr_GInfo,Info,gadget->Flags & GFLG_SELECTED,gadget->Flags & GFLG_DISABLED);
  808.  
  809.     return(TRUE);
  810. }
  811.  
  812. STATIC VOID
  813. DisposeMethod(
  814.     struct IClass *    class,
  815.     Object *        object,
  816.     Msg                msg)
  817. {
  818.     PopInfo *Info = INST_DATA(class,object);
  819.  
  820.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  821.  
  822.     if(Info->Font != NULL)
  823.     {
  824.         CloseFont(Info->Font);
  825.         Info->Font = NULL;
  826.     }
  827.  
  828.     if(Info->Window != NULL)
  829.     {
  830.         CloseWindow(Info->Window);
  831.         Info->Window = NULL;
  832.     }
  833.  
  834.     LTP_DeleteCheckGlyph(Info->CheckGlyph);
  835.     Info->CheckGlyph = NULL;
  836.  
  837.     if(Info->FrameImage != NULL)
  838.     {
  839.         DisposeObject(Info->FrameImage);
  840.         Info->FrameImage = NULL;
  841.     }
  842. }
  843.  
  844. STATIC ULONG
  845. NewMethod(
  846.     struct IClass *    class,
  847.     Object *        object,
  848.     struct opSet *    SetInfo)
  849. {
  850.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  851.  
  852.     object = (Object *)DoSuperMethodA(class,object,(Msg)SetInfo);
  853.     if(object != NULL)
  854.     {
  855.         PopInfo *            Info = INST_DATA(class,object);
  856.         struct TagItem *    Item;
  857.         struct TagItem *    TagList = SetInfo -> ops_AttrList;
  858.         struct TextAttr    *    Font = NULL;
  859.         LONG                Width = 0;
  860.         LONG                Height = 0;
  861.         LONG                AspectX = 1;
  862.         LONG                AspectY = 1;
  863.  
  864.         memset(Info,0,sizeof(PopInfo));
  865.  
  866.         while((Item = NextTagItem(&TagList)) != NULL)
  867.         {
  868.             switch(Item->ti_Tag)
  869.             {
  870.                 case GA_Width:
  871.                     Width = Item->ti_Data;
  872.                     break;
  873.  
  874.                 case GA_Height:
  875.                     Height = Item->ti_Data;
  876.                     break;
  877.  
  878.                 case PIA_Labels:
  879.                     Info->Labels = (STRPTR *)Item->ti_Data;
  880.                     break;
  881.  
  882.                 case PIA_Active:
  883.                     Info->Active = (LONG)Item->ti_Data;
  884.                     break;
  885.  
  886.                 case PIA_Font:
  887.                     Font = (struct TextAttr *)Item->ti_Data;
  888.                     break;
  889.  
  890.                 case PIA_CentreActive:
  891.                     Info->CentreActive = Item->ti_Data;
  892.                     break;
  893.  
  894.                 case PIA_AspectX:
  895.                     AspectX = Item->ti_Data;
  896.                     break;
  897.  
  898.                 case PIA_AspectY:
  899.                     AspectY = Item->ti_Data;
  900.                     break;
  901.             }
  902.         }
  903.  
  904.         Info->AspectX = AspectX;
  905.         Info->AspectY = AspectY;
  906.  
  907.         if(V39)
  908.         {
  909.             Info->FrameImage = (struct Image *)NewObject(NULL,FRAMEICLASS,
  910.                 IA_Width,        Width,
  911.                 IA_Height,        Height,
  912.                 IA_FrameType,    FRAME_BUTTON,
  913.             TAG_DONE);
  914.         }
  915.  
  916.         if(Font && Info->Labels != NULL && Info->Labels != (STRPTR *)~0 && Width && Height)
  917.         {
  918.             while(Info->Labels[Info->NumLabels])
  919.                 Info->NumLabels++;
  920.  
  921.             if(Info->NumLabels)
  922.             {
  923.                 Info->Font = OpenFont(Font);
  924.                 if(Info->Font != NULL)
  925.                 {
  926.                     struct RastPort RPort;
  927.  
  928.                     if(Info->Active < 0)
  929.                     {
  930.                         Info->Active = 0;
  931.                     }
  932.                     else
  933.                     {
  934.                         if(Info->Active >= Info->NumLabels)
  935.                             Info->Active = Info->NumLabels - 1;
  936.                     }
  937.  
  938.                     InitRastPort(&RPort);
  939.                     SetFont(&RPort,Info->Font);
  940.  
  941.                     Info->PickerWidth = LTP_GetPickerWidth(Font->ta_YSize,AspectX,AspectY);
  942.  
  943.                     Info->ArrowWidth    = (TextLength(&RPort,"M",1) & ~1) + 1;
  944.                     Info->ArrowHeight    = (2 * RPort.TxHeight) / 3;
  945.                     Info->ArrowTop        = (Height - Info->ArrowHeight) / 2;
  946.  
  947.                     Info->MarkWidth    = Info->PickerWidth;
  948.                     Info->MarkLeft    = 4 + Info->MarkWidth;
  949.  
  950.                     Info->PopLeft    = 0;
  951.                     Info->PopWidth    = Width;
  952.  
  953.                     Info->LabelTop    = (Height - RPort.TxHeight) / 2;
  954.  
  955.                     Width    -= 6 + Info->MarkWidth + 6;
  956.                     Height    -= 2 + RPort.TxHeight + 2;
  957.  
  958.                     if(Width > 0 && Height >= 0)
  959.                     {
  960.                         struct TextExtent    Extent;
  961.                         LONG                i,Len,MaxLen;
  962.  
  963.                         for(i = MaxLen = 0 ; i < Info->NumLabels ; i++)
  964.                         {
  965.                             Len = TextFit(&RPort,Info->Labels[i],strlen(Info->Labels[i]),&Extent,NULL,1,Width,32767);
  966.  
  967.                             if(Len > MaxLen)
  968.                                 MaxLen = Len;
  969.                         }
  970.  
  971.                         if(MaxLen)
  972.                         {
  973.                             Len = strlen(Info->Labels[Info->Active]);
  974.  
  975.                             if(Len > MaxLen)
  976.                                 Len = MaxLen;
  977.  
  978.                             Info->ActiveLen = Len;
  979.  
  980.                             Info->MaxLen    = MaxLen;
  981.                             Info->MaxWidth    = Width;
  982.  
  983.                             return((ULONG)object);
  984.                         }
  985.                     }
  986.  
  987.                     CloseFont(Info->Font);
  988.                     Info->Font = NULL;
  989.                 }
  990.             }
  991.         }
  992.  
  993.         CoerceMethod(class,object,OM_DISPOSE);
  994.     }
  995.  
  996.     return(0);
  997. }
  998.  
  999. STATIC ULONG
  1000. ActiveMethod(
  1001.     struct IClass *        class,
  1002.     struct Gadget *        gadget,
  1003.     struct gpInput *    InputInfo)
  1004. {
  1005.     PopInfo *            Info = INST_DATA(class,gadget);
  1006.     struct RastPort *    RPort;
  1007.     struct GadgetInfo *    GInfo;
  1008.  
  1009.     if(Info->Blocked || (gadget->Flags & GFLG_DISABLED))
  1010.         return(GMR_NOREUSE);
  1011.  
  1012.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  1013.  
  1014.     GInfo = InputInfo->gpi_GInfo;
  1015.  
  1016.     RPort = ObtainGIRPort(GInfo);
  1017.     if(RPort != NULL)
  1018.     {
  1019.         LONG Left,Top;
  1020.  
  1021.         Left    = gadget->LeftEdge;
  1022.         Top        = gadget->TopEdge;
  1023.  
  1024.         Info->Window = NULL;
  1025.  
  1026.         if(Info->NumLabels > 2 && InputInfo->gpi_Mouse.X < gadget->Width - Info->MarkLeft && V39)
  1027.         {
  1028.             LONG SingleHeight,ScreenHeight,Width,Height;
  1029.  
  1030.             Info->Flags &= ~PIF_SingleActive;
  1031.             Info->Window = NULL;
  1032.  
  1033.             SetFont(RPort,Info->Font);
  1034.  
  1035.             SingleHeight = gadget->Height;
  1036.             ScreenHeight = GInfo->gi_Screen->Height;
  1037.  
  1038.             Info->LineTop = (SingleHeight - RPort->TxHeight) / 2;
  1039.  
  1040.             Width    = Info->PopWidth;
  1041.             Height    = 2 + SingleHeight * Info->NumLabels + 2;
  1042.  
  1043.             while(Height > SingleHeight && Height > ScreenHeight)
  1044.                 Height -= SingleHeight;
  1045.  
  1046.             if(Height > SingleHeight)
  1047.             {
  1048.                 struct DrawInfo *DrawInfo;
  1049.                 UWORD *Pens;
  1050.                 LONG LeftEdge,TopEdge;
  1051.                 LONG TopMost;
  1052.                 LONG Plus;
  1053.  
  1054.                 LeftEdge    = GInfo->gi_Window->LeftEdge + Left + Info->PopLeft;
  1055.                 TopEdge        = GInfo->gi_Window->TopEdge + Top + Info->LabelTop - (2 + Info->LineTop + Info->Active * SingleHeight);
  1056.                 TopMost        = 0;
  1057.  
  1058.                 if(Info->CentreActive)
  1059.                     Plus = 1;
  1060.                 else
  1061.                     Plus = 0;
  1062.  
  1063.                 while(TopEdge < 0 && TopMost < Info->NumLabels)
  1064.                 {
  1065.                     TopEdge    += SingleHeight;
  1066.                     TopMost    += Plus;
  1067.                 }
  1068.  
  1069.                 DrawInfo = GInfo->gi_DrInfo;
  1070.                 Pens = DrawInfo->dri_Pens;
  1071.  
  1072.                 if(V39)
  1073.                 {
  1074.                     Info->MenuText = Pens[BARDETAILPEN];
  1075.                     Info->MenuBack = Pens[BARBLOCKPEN];
  1076.                 }
  1077.                 else
  1078.                 {
  1079.                     Info->MenuText = Pens[DETAILPEN];
  1080.                     Info->MenuBack = Pens[BLOCKPEN];
  1081.                 }
  1082.  
  1083.                 Info->CheckGlyph = LTP_CreateCheckGlyph((RPort->TxHeight * DrawInfo->dri_Resolution.Y) / DrawInfo->dri_Resolution.X,RPort->TxHeight,GInfo->gi_Window->RPort->BitMap,Info->MenuText,Info->MenuBack);
  1084.  
  1085.                 if((Info->CheckGlyph != NULL) && (TopEdge >= 0) && (TopMost < Info->NumLabels))
  1086.                 {
  1087.                     while((Height > SingleHeight) && (TopEdge + Height > ScreenHeight))
  1088.                         Height -= SingleHeight;
  1089.  
  1090.                     if((Height > SingleHeight) && (TopEdge + Height <= ScreenHeight))
  1091.                     {
  1092.                         ReleaseGIRPort(RPort);
  1093.  
  1094.                         Info->Window = OpenWindowTags(NULL,
  1095.                             WA_Left,            LeftEdge,
  1096.                             WA_Top,                TopEdge,
  1097.                             WA_Width,            Width,
  1098.                             WA_Height,            Height,
  1099.                             WA_SimpleRefresh,    TRUE,
  1100.                             WA_NoCareRefresh,    TRUE,
  1101.                             WA_AutoAdjust,        FALSE,
  1102.                             WA_CustomScreen,    GInfo->gi_Screen,
  1103.                             WA_Borderless,        TRUE,
  1104.  
  1105.                             V39 ? WA_BackFill : TAG_IGNORE,LAYERS_NOBACKFILL,
  1106.                         TAG_DONE);
  1107.                         if(Info->Window != NULL)
  1108.                         {
  1109.                             Info->TopMost        = TopMost;
  1110.  
  1111.                             Info->BoxLeft        = LeftEdge + 4;
  1112.                             Info->BoxTop        = TopEdge + 2;
  1113.                             Info->BoxWidth        = Width - 8;
  1114.                             Info->BoxHeight        = Height - 4;
  1115.  
  1116.                             Info->BoxLines        = Info->BoxHeight / SingleHeight;
  1117.  
  1118.                             Info->SingleWidth    = Width - 8;
  1119.                             Info->SingleHeight    = SingleHeight;
  1120.  
  1121.                             if(V39)
  1122.                             {
  1123.                                 STATIC const BYTE RenderPens[] =
  1124.                                 {
  1125.                                     BACKGROUNDPEN,
  1126.                                     FILLPEN,
  1127.                                     TEXTPEN,
  1128.                                     FILLTEXTPEN,
  1129.                                     SHADOWPEN,
  1130.                                     SHINEPEN,
  1131.                                     BARDETAILPEN,
  1132.                                     BARBLOCKPEN
  1133.                                     -1
  1134.                                 };
  1135.  
  1136.                                 LONG i,Pen,Max = 0;
  1137.  
  1138.                                 Info->MenuTextSelect    = Pens[BARBLOCKPEN];
  1139.                                 Info->MenuBackSelect    = Pens[BARDETAILPEN];
  1140.  
  1141.                                 for(i = 0 ; RenderPens[i] != -1 ; i++)
  1142.                                 {
  1143.                                     if((Pen = Pens[RenderPens[i]]) > Max)
  1144.                                         Max = Pen;
  1145.                                 }
  1146.  
  1147.                                 SetMaxPen(Info->Window->RPort,Max);
  1148.                             }
  1149.                             else
  1150.                             {
  1151.                                 Info->MenuTextSelect    = ~Pens[DETAILPEN];
  1152.                                 Info->MenuBackSelect    = ~Pens[BLOCKPEN];
  1153.                             }
  1154.  
  1155.                             SetFont(Info->Window->RPort,Info->Font);
  1156.                         }
  1157.  
  1158.                         RPort = ObtainGIRPort(GInfo);
  1159.                         if(RPort == NULL)
  1160.                         {
  1161.                             if(Info->Window != NULL)
  1162.                             {
  1163.                                 CloseWindow(Info->Window);
  1164.                                 Info->Window = NULL;
  1165.                             }
  1166.                         }
  1167.                     }
  1168.                 }
  1169.             }
  1170.         }
  1171.  
  1172.         if(Info->Window == NULL)
  1173.         {
  1174.             LTP_DeleteCheckGlyph(Info->CheckGlyph);
  1175.             Info->CheckGlyph = NULL;
  1176.  
  1177.             Info->Flags |= PIF_SingleActive;
  1178.         }
  1179.  
  1180.         if(((Info->Flags & PIF_SingleActive) || (Info->Window != NULL)) && (RPort != NULL))
  1181.         {
  1182.             Info->InitialActive = Info->Active;
  1183.  
  1184.             gadget->Flags |= GFLG_SELECTED;
  1185.  
  1186.             if(!Info->CheckGlyph)
  1187.                 DoMethod((Object *)gadget,GM_RENDER,GInfo,RPort,GREDRAW_UPDATE);
  1188.  
  1189.             ReleaseGIRPort(RPort);
  1190.  
  1191.             if(Info->Window)
  1192.                 BoxRender(Info,GInfo->gi_DrInfo->dri_Pens,Info->Active,TRUE,TRUE,0);
  1193.  
  1194.             return(GMR_MEACTIVE);
  1195.         }
  1196.  
  1197.         if(RPort != NULL)
  1198.             ReleaseGIRPort(RPort);
  1199.     }
  1200.  
  1201.     return(GMR_NOREUSE);
  1202. }
  1203.  
  1204. STATIC ULONG
  1205. InactiveMethod(
  1206.     struct IClass *            class,
  1207.     struct Gadget *            gadget,
  1208.     struct gpGoInactive *    InactiveInfo)
  1209. {
  1210.     PopInfo *Info = INST_DATA(class,gadget);
  1211.  
  1212.     DB(kprintf("%s %ld\n",__FUNC__,__LINE__));
  1213.  
  1214.     gadget->Flags &= ~GFLG_SELECTED;
  1215.  
  1216.     if((Info->Window != NULL) || (Info->Flags & PIF_SingleActive))
  1217.     {
  1218.         struct RastPort    *RPort;
  1219.  
  1220.         if(Info->Window)
  1221.         {
  1222.             CloseWindow(Info->Window);
  1223.             Info->Window = NULL;
  1224.         }
  1225.  
  1226.         if(!Info->CheckGlyph)
  1227.         {
  1228.             if(RPort = ObtainGIRPort(InactiveInfo->gpgi_GInfo))
  1229.             {
  1230.                 DoMethod((Object *)gadget,GM_RENDER,InactiveInfo->gpgi_GInfo,RPort,GREDRAW_UPDATE);
  1231.                 ReleaseGIRPort(RPort);
  1232.             }
  1233.         }
  1234.  
  1235.         LTP_DeleteCheckGlyph(Info->CheckGlyph);
  1236.         Info->CheckGlyph = NULL;
  1237.  
  1238.         Info->Flags &= ~PIF_SingleActive;
  1239.     }
  1240.  
  1241.     return(0);
  1242. }
  1243.  
  1244. ULONG SAVE_DS ASM
  1245. LTP_PopupClassDispatcher(
  1246.     REG(a0) struct IClass *    class,
  1247.     REG(a2) Object *        object,
  1248.     REG(a1) Msg                msg)
  1249. {
  1250.     switch(msg->MethodID)
  1251.     {
  1252.         case OM_NEW:
  1253.             return(NewMethod(class,object,(struct opSet *)msg));
  1254.  
  1255.         case OM_UPDATE:
  1256.         case OM_SET:
  1257.             SetMethod(class,(struct Gadget *)object,(struct opSet *)msg);
  1258.             break;
  1259.  
  1260.         case GM_RENDER:
  1261.             return(RenderMethod(class,(struct Gadget *)object,(struct gpRender *)msg));
  1262.  
  1263.         case GM_HITTEST:
  1264.             return(GMR_GADGETHIT);
  1265.  
  1266.         case GM_GOINACTIVE:
  1267.             return(InactiveMethod(class,(struct Gadget *)object,(struct gpGoInactive *)msg));
  1268.  
  1269.         case GM_GOACTIVE:
  1270.             return(ActiveMethod(class,(struct Gadget *)object,(struct gpInput *)msg));
  1271.  
  1272.         case GM_HANDLEINPUT:
  1273.             return(InputMethod(class,(struct Gadget *)object,(struct gpInput *)msg));
  1274.  
  1275.         case OM_DISPOSE:
  1276.             DisposeMethod(class,object,msg);
  1277.  
  1278.             // Falls down to the default case...
  1279.     }
  1280.  
  1281.     return(DoSuperMethodA(class,object,msg));
  1282. }
  1283.  
  1284. #endif    /* DO_POPUP_KIND */
  1285.